﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using RegExStudio.RegExStudioEventArgs;

namespace RegExStudio.UserControls
{
    /// <summary>
    /// Fasste die Eingabe / Ergebniscontrols zusammen und macht sie benutzbar
    /// </summary>
    public partial class CtrlRegEx : UserControl
    {
        private Xml.RegExSetRegEx _regEx;
        /// <summary>
        /// Die RegEx aus dem RegExSet das geladen/bearbeitet/gespeichert wird
        /// </summary>
        public Xml.RegExSetRegEx RegEx
        {
            get { return _regEx; }
        }

        /// <summary>
        /// ctor
        /// </summary>
        /// <param name="regEx">Das RegExSet das geladen/bearbeitet/gespeichert wird</param>
        public CtrlRegEx(Xml.RegExSetRegEx regEx)
        {
            InitializeComponent();
            _regEx = regEx;
        }

        /// <summary>
        /// Initialisiert das Control mit dem RegExSet das im ctor angegeben wurde
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void CtrlRegEx_Load(object sender, EventArgs e)
        {
            //Anzeigen und verarbeiten
            ctrlHeader.RegExName = _regEx.Name;
            ctrlPattern.Pattern = _regEx.Pattern;
            ctrlPattern.Options = (RegexOptions)_regEx.Options;
            ctrlInput.Input = _regEx.Input;
            ctrlInput.Replacements = _regEx.Replacements;
            ctrlResult.DataSource = resultsDataSet;
            ProcessRegEx();

            //Auf Änderungen reagieren (Wird erst hier gemacht, da sonst beim Laden der RegEx 4 mal die Methode ProcessRegEx() uafgerufen werden würde
            ctrlPattern.PatternChanged += new CtrlPattern.PatternChangedEventHandler(ctrlPattern_PatternChanged);
            ctrlPattern.OptionsChanged += new CtrlPattern.OptionsChangedEventHandler(ctrlPattern_OptionsChanged);
            ctrlInput.InputChanged += new CtrlInput.InputChangedEventHandler(ctrlInput_InputChanged);
            ctrlInput.ReplacementChanged += new CtrlInput.ReplacementChangedEventHandler(ctrlInput_ReplacementChanged);
        }

        /// <summary>
        /// Der Name der RegEx wurde geändert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlHeader_NameChanged(object sender, NameChangedEventArgs e)
        {
            _regEx.Name = e.Name;
            OnRegExChanged();
        }
        
        private void ctrlHeader_MatchChanged(object sender, MatchChangedEventArgs e)
        {
            ProcessRegEx();
        }

        /// <summary>
        /// Das Pattern der RegEx wurde geändert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlPattern_PatternChanged(object sender, PatternChangedEventArgs e)
        {
            _regEx.Pattern = e.Pattern;

            OnRegExChanged();

            ProcessRegEx();
        }

        /// <summary>
        /// Die Optionen der RegEx wurde geändert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlPattern_OptionsChanged(object sender, OptionsChangedEventArgs e)
        {
            _regEx.Options = (uint)e.Options;

            OnRegExChanged();

            ProcessRegEx();
        }

        /// <summary>
        /// Der Eingabewert der RegEx wurde geändert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlInput_InputChanged(object sender, InputChangedEventArgs e)
        {
            _regEx.Input = e.Input;

            OnRegExChanged();

            ProcessRegEx();
        }

        /// <summary>
        /// Die Replacements der RegEx wurde geändert
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlInput_ReplacementChanged(object sender, ReplacementsChangedEventArgs e)
        {
            _regEx.Replacements = e.Replacements;

            OnRegExChanged();

            ProcessRegEx();
        }

        /// <summary>
        /// Vom Resultsgrid kam das Event, einen Bereich in der Eingabe zu markieren
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ctrlResult_GoToSelection(object sender, GoToSelectionEventArgs e)
        {
            ctrlInput.Select(e.Index, e.Length);
        }

        /// <summary>
        /// EventHandler für Änderung einer RegEx
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public delegate void RegExChangedEventHandler(object sender, RegExChangedEventArgs e);

        /// <summary>
        /// Event das ausgelöst wird, wenn eine RegEx geändert wurde
        /// </summary>
        public event RegExChangedEventHandler RegExChanged;

        /// <summary>
        /// Feuert das Event, wenn eine RegEx geändert wurde
        /// </summary>
        protected virtual void OnRegExChanged()
        {
            if (RegExChanged != null)
            {
                RegExChanged(this, new RegExChangedEventArgs(_regEx));
            }
        }

        private void ClearResults()
        {
            //Alle Anzeigen zurücksetzen
            resultsDataSet.Groups.Clear();
            resultsDataSet.Captures.Clear();
            resultsDataSet.Splits.Clear();
            resultsDataSet.AcceptChanges();

            ctrlInput.ClearFormat();

            ctrlResult.ReplacedText = string.Empty;

            ctrlHeader.MatchWarningVisible = false;
            ctrlPattern.WarningVisible = false;
        }

        /// <summary>
        /// Verarbeitet die RegEx mit den Optionen und den Eingabewerten
        /// </summary>
        public void ProcessRegEx()
        {
            //Ergebnisse clearen
            ClearResults();

            //RegEx aus der EIngabe Objekt erzeugen
            System.Text.RegularExpressions.Regex regEx = null;
            try
            {
                regEx = new System.Text.RegularExpressions.Regex(ctrlPattern.Pattern, ctrlPattern.Options);
            }
            catch (ArgumentException)
            {
                ctrlPattern.WarningVisible = true;
                return;
            }

            //Ohne Pattern oder Input wird nix gemacht
            if (ctrlPattern.Pattern == string.Empty || ctrlInput.Input == string.Empty)
            {
                return;
            }

            if (regEx.IsMatch(ctrlInput.Input))
            {  
                MatchCollection matches = regEx.Matches(ctrlInput.Input);

                if (ctrlHeader.Match < matches.Count)
                {
                    Match match = matches[ctrlHeader.Match];
                    if (match.Groups[0].Value != string.Empty)
                    {
                        for (int nGroup = 0; nGroup < match.Groups.Count; nGroup++)
                        {
                            string groupName = regEx.GroupNameFromNumber(nGroup);

                            Group grp = match.Groups[nGroup];

                            Color colorGrp = ColorManager.Instance.GetColor(nGroup);

                            resultsDataSet.Groups.AddGroupsRow(groupName, nGroup, grp.Value, grp.Index, grp.Length, grp.Captures.Count, colorGrp);

                            for (int nCapture = 0; nCapture < grp.Captures.Count; nCapture++)
                            {
                                Color colorCap = ColorManager.Instance.GetGradientColor(colorGrp, nCapture);

                                ctrlInput.Format(grp.Captures[nCapture].Index, grp.Captures[nCapture].Length, colorCap);

                                resultsDataSet.Captures.AddCapturesRow(nGroup, nCapture, grp.Captures[nCapture].Value, grp.Captures[nCapture].Index, grp.Captures[nCapture].Length, colorCap);
                            }
                        }

                        //Die Splitfunktion anwenden
                        string[] splits = regEx.Split(ctrlInput.Input);
                        for (int nSplit = 0; nSplit < splits.Count() - 1; nSplit++)
                        {
                            resultsDataSet.Splits.AddSplitsRow(nSplit, splits[nSplit]);
                        }

                        //Replace anwenden
                        ctrlResult.ReplacedText = regEx.Replace(ctrlInput.Input, ctrlInput.Replacements);
                    }
                }
                else //if (ctrlHeader.Match <= matches.Count-1)
                {
                    ctrlHeader.MatchWarningVisible = true;
                }
            }
            else
            {
            }
        }

        /// <summary>
        /// Vergrößert die Schriftart im Input Control
        /// </summary>
        public void IncreaseFont()
        {
            ctrlInput.IncreaseFont();
        }

        //Verkleinert die Schriftart im Input Control
        public void DecreaseFont()
        {
            ctrlInput.DecreaseFont();
        }


    }
}
